﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using Newtonsoft.Json.Linq;
using LogLib;
using DeviceCommon;

namespace PassportReaderAPI
{
    public class PassportReader : DeviceBase
    { 
        private PRSDK _sdk = new PRSDK();
     
        private string _imageFilePath = "";

        private PassportReaderOption _option = new PassportReaderOption();

        private Polling poll = null;
      
        /// <summary>
        /// 当前待识别证件的类型
        /// </summary>
        private int CurrentIDCardType = 13;

        /// <summary>
        /// 护照类型，台胞证或外国人
        /// </summary>
        private string PassportType = "TaiBao";

        public PassportReader()
        {
            InitOption();
        }

        private void InitOption()
        {
            if (!File.Exists(_option.ConfigFilePath))
            {
                _option.Save();
            }
            _option.Load();
        }

        protected override void OnWorkingCompleted(string outParams)
        {
            base.OnWorkingCompleted(outParams);
        }

        protected override void OnWorkingFailed(string message)
        {
            base.OnWorkingFailed(message);
        }

        public override void Init(string param, out string outParam)
        {
            outParam = "";
            if (_bInited)
            {
                return;
            }
            Log.WriteAsync("Start Init");
            // 读取授权码
            string userID = _option.UserId;
            string dllDir = _option.DllDir;
            if (_sdk.LoadKernal(dllDir, userID))
            {
                _bInited = true;
                _bExited = false;
                Log.WriteAsync(string.Format("护照阅读机初始化成功"));              
            }
            else
            {
                _error= string.Format("护照阅读机初始化失败: {0}", _sdk.ErrorMessage);
                Log.WriteAsync(_error);
                _bInited = false;
                _bExited = true;
            }
            Log.WriteAsync("End Init");       
        }

        public override bool DoAction(string param, out string outParam)
        {
            outParam = "";
            _error = "";
            JObject inParam = JObject.Parse(param);
            _imageFilePath = (string)inParam["ImagePath"];
            poll = new Polling(TakeLastEntryStamp, param);
            poll.TimeoutMilliSecond = TimeoutMillisecond;
            poll.ScanInterval = _option.ReadInterval;
            poll.Start(OnWorkingCompleted);
            return true;
        }

        public override void Start(string param, out string outParam)
        {
            outParam = "";
            CurrentIDCardType = 13;
            JObject inParam = JObject.Parse(param);
            _imageFilePath = (string)inParam["ImagePath"];
            CurrentIDCardType = Convert.ToInt32((string)inParam["IDCardType"]);
            Log.WriteAsync("CurrentIDCardType:" + CurrentIDCardType.ToString());
            PassportType = (string)inParam["PassportType"];
            if (!_sdk.CheckDeviceConnected())
            {
                _error = "设备未连接";
                Log.WriteAsync(_error);
                return;
            }
            if (CurrentIDCardType == 12 || CurrentIDCardType == 13)  // 读护照或签证
            {
                if (string.IsNullOrEmpty(_imageFilePath) || !Directory.Exists(_imageFilePath))
                {
                    _error = "路径为空或不存在的路径" + _imageFilePath;
                    Log.WriteAsync(_error);
                    return;
                }
                poll = new Polling(Read, param);
                poll.TimeoutMilliSecond = TimeoutMillisecond;
                poll.ScanInterval = _option.ReadInterval;
                poll.Start(OnWorkingCompleted);
            }
            else if(CurrentIDCardType == 111) // 拍摄入境章
            {
                poll = new Polling(TakeLastEntryStamp, param);
                poll.TimeoutMilliSecond = TimeoutMillisecond;
                poll.ScanInterval = _option.ReadInterval;
                poll.Start(OnWorkingCompleted);
            }
            else
            {
                Log.WriteAsync($"例外的证件类型{CurrentIDCardType}");
                poll = new Polling(Read, param);
                poll.TimeoutMilliSecond = TimeoutMillisecond;
                poll.ScanInterval = _option.ReadInterval;
                poll.Start(OnWorkingCompleted);
            }
        }

        public override void Stop(string param, out string outParam)
        {
            outParam = "";
            if (poll != null)
            {
                poll.Stop();
                poll.Dispose();
                poll = null;
            }
        }

        public override void Exit(string inParams, out string outParam)
        {
            outParam = "";
            try
            {
                _sdk.FreeKernal();
                _bExited = true;
                _state = DeviceState.NotInitialized;
            }
            catch (Exception ex)
            {
                Log.WriteException(ex.ToString());
            }
            finally
            {
                _bInited = false;
            }
        }

        /// <summary>
        /// 执行单次读取身份证操作
        /// </summary>
        /// <param name="initiative">TRUE:表示只进行单次读取；False:表示循坏读取，直到读取成功则停止循环</param>
        /// <returns></returns>
        public bool Read(string inParams, out string outParams)
        {
            outParams = "";
            if (!_bInited)
            {
                return false;
            }
            bool readSuccess = false;
            _error = "";
            try
            {
                int existsFlag = 0;
                if (!_sdk.CheckExistDocument(ref existsFlag))
                {
                    // 2表示证件被拿出
                    // 0表示无信号，一般发生在证件刚被取走的瞬间
                    // 1表示有信号
                    if (existsFlag == 0
                        || existsFlag == 2
                        || existsFlag == 3)
                    {
                        Thread.Sleep(_option.ReadInterval);
                        return false;
                    }
                }
                if (OnReading(CurrentIDCardType, out outParams))
                {
                    readSuccess = true;
                }
                return readSuccess;
            }
            catch (Exception ex)
            {
                _error = string.Format("读取护照信息发生了异常.\n异常详情:{0}", ex.ToString());
                Log.WriteException(_error);
                return false;
            }
        }

        /// <summary>
        /// 读本动作
        /// </summary>
        /// <returns></returns>
        private bool OnReading(int IDCardType, out string recogRes)
        {
            _error = "";
            recogRes = "";
            int i = 0;
            try
            {
                do
                {
                    if (_sdk.ScanAndRecog(IDCardType, _imageFilePath, out recogRes))
                    {
                        if (PassportType == "Foreign")
                        {
                            JObject param = JObject.Parse(recogRes);  //add by cyy on 0610
                            if (!string.IsNullOrEmpty((string)param["MRZ1"]) && !string.IsNullOrEmpty((string)param["MRZ2"]))
                            {
                                // 读取护照信息成功   
                                Log.WriteAsync("读取成功:" + recogRes);
                                return true;
                            }
                            else
                            {
                                Log.WriteAsync("读取成功: 但MRZ1或MRZ2为空");
                            }
                        }
                        else
                        {
                            // 读取护照信息成功   
                            Log.WriteAsync("读取成功:" + recogRes);
                            return true;
                        }
                    }
                    Log.WriteAsync("识别失败！识别次数=" + (i+1).ToString());
                    Thread.Sleep(1000);
                } while ((i++) <= _option.RetryTimes + 1); // 读本失败进行重试
            }
            catch (System.Exception ex)
            {
                _error = ex.ToString();
                Log.WriteAsync("读取完成，结果是失败:" + _error);
                return false;
            }
            _error = _sdk.ErrorMessage;
            Log.WriteAsync("读取完成，结果是失败:" + _error);
            return false;
        }

        private bool TakeLastEntryStamp(string inParams, out string outParamString)
        {
            outParamString = "";
            Log.WriteAsync("进入TakeLastEntryStamp线程");
            int existsFlag = 0;
            if (!_sdk.CheckExistDocument(ref existsFlag))
            {
                // 2表示证件被拿出
                // 0表示无信号，一般发生在证件刚被取走的瞬间
                // 1表示有信号
                if (existsFlag == 0
                    || existsFlag == 2
                    || existsFlag == 3)
                {
                    Thread.Sleep(_option.ReadInterval);
                    Log.WriteAsync("离开TakeLastEntryStamp线程");
                    return false;
                }
            }
            if (OnPhotoTaking(out outParamString))
            {
                Log.WriteAsync("离开TakeLastEntryStamp线程");
                return true;
            }
            Log.WriteAsync("离开TakeLastEntryStamp线程");
            return false;
        }

        /// <summary>
        /// 拍照动作
        /// </summary>
        /// <returns></returns>
        private bool OnPhotoTaking(out string outParamString)
        {
            JObject result = new JObject();
            outParamString = "";
            _error = "";
            int i = 0;
            result.Add("GrabSignalType", 1);
            do
            {
                if (_sdk.AcquireAndSaveImage(_imageFilePath))
                {
                    result.Add("PhotoPath", _imageFilePath);
                    outParamString = result.ToString();
                    Log.WriteAsync("照片拍摄成功.");
                    return true;
                }
                Thread.Sleep(500);
            } while ((i++) <= _option.RetryTimes + 1); // 拍照失败进行重试
            _error = _sdk.ErrorMessage;
            Log.WriteAsync("拍照失败:" + _error);            
            return false;
        }

        public override void ShowConfigDialog(string inParam)
        {
            FormSetting form = new FormSetting();
            form.ShowDialog();
        }
    }
}
